/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.component.raspberrypi.gpio.pwm;

import cn.hutool.core.util.ObjUtil;
import com.pi4j.context.Context;
import com.pi4j.io.gpio.digital.DigitalInput;
import com.pi4j.io.gpio.digital.DigitalState;
import com.pi4j.io.gpio.digital.PullResistance;
import com.pi4j.io.pwm.Pwm;
import com.pi4j.io.pwm.PwmType;
import lombok.AccessLevel;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;

/**
 * <b>(RaspberryPiRGBLed)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2023/2/20
 */
@SuppressWarnings({"unused", "AlibabaClassNamingShouldBeCamel"})
@FieldDefaults(level = AccessLevel.PRIVATE)
@Accessors(chain = true)
@Controller
@Mapping("/rgb")
public class RaspberryPiRGBLed {
    @Inject
    Context pi4j;
    Pwm ledRed;
    Pwm ledGreen;
    Pwm ledBlue;
    static final int PIN_LED_B  = 23;
    static final int PIN_LED_G  = 24;
    static final int PIN_LED_R  = 25;
    static final int PIN_BUTTON = 26;

    @Mapping("/")
    public void index(org.noear.solon.core.handle.Context ctx) {
        init();
        //内部跳转到 /index.htm
        ctx.forward("/raspberry/pwm/RaspberryPiRGBLed.html");
    }

    @Mapping("/led")
    public void led(String state) {
        var color = "";

        switch (state) {
            case "red":
                change(true, false, false);
                color = "Led turn Red";
                break;
            case "green":
                change(false, true, false);
                color = "Led turn Green";
                break;
            case "blue":
                change(false, false, true);
                color = "Led turn Blue";
                break;
            case "neon":
                neon();
                color = "Led Neon";
                break;
            case "":
            default:
                change(false, false, false);
                color = "Led turn off";
                break;
        }

        System.out.println(color);
    }

    @Mapping("/mix")
    public void mix(String state) {
        var color = "";
        switch (state) {
            case "purple":
                purple();
                color = "Led turn purple";
                break;
            case "white":
                white();
                color = "Led turn white";
                break;
            case "greenTurkey":
                greenTurkey();
                color = "Led turn greenTurkey";
                break;
            case "":
            default:
                change(false, false, false);
                color = "Led turn off";
                break;
        }
    }

    private void init() {
        if (ObjUtil.isAllEmpty(ledRed, ledGreen, ledBlue)) {
            initLed();
            initButton();
        }
    }

    private void initLed() {

        var ledRedConfig = Pwm.newConfigBuilder(pi4j)
                .id("BCM" + PIN_LED_R)
                .name("LED_RED")
                .address(PIN_LED_R)
                .pwmType(PwmType.SOFTWARE)
                .initial(0)
                .shutdown(0)
                .provider("pigpio-pwm")
                .build();

        var ledGreenConfig = Pwm.newConfigBuilder(pi4j)
                .id("BCM" + PIN_LED_G)
                .name("LED_GREEN")
                .address(PIN_LED_G)
                .pwmType(PwmType.SOFTWARE)
                .initial(0)
                .shutdown(0)
                .provider("pigpio-pwm")
                .build();

        var ledBlueConfig = Pwm.newConfigBuilder(pi4j)
                .id("BCM" + PIN_LED_B)
                .name("LED_BLUE")
                .address(PIN_LED_B)
                .pwmType(PwmType.SOFTWARE)
                .initial(0)
                .shutdown(0)
                .provider("pigpio-pwm")
                .build();

        ledRed = pi4j.create(ledRedConfig);
        ledGreen = pi4j.create(ledGreenConfig);
        ledBlue = pi4j.create(ledBlueConfig);
    }

    private void initButton() {
        var buttonConfig = DigitalInput.newConfigBuilder(pi4j)
                .id("button")
                .name("Press button")
                .address(PIN_BUTTON)
                .pull(PullResistance.PULL_DOWN)
                .debounce(3000L)
                .provider("pigpio-digital-input");
        DigitalInput button = pi4j.create(buttonConfig);
        button.addListener(e -> {
            if (e.state() == DigitalState.LOW) {

                if (ledRed.isOff() && ledGreen.isOff() && ledBlue.isOff()) {
                    change(true, false, false);
                    return;
                }

                if (ledRed.isOn()) {
                    change(false, true, false);
                    return;
                }

                if (ledGreen.isOn()) {
                    change(false, false, true);
                    return;
                }

                if (ledBlue.isOn()) {
                    change(false, false, false);
                    return;
                }
            }
        });
    }

    private void neon() {
        int i = 0;
        while (i < 5) {
            i++;

            change(true, false, false);
            delay(200);

            change(false, true, false);
            delay(200);

            change(false, false, true);
            delay(200);

            change(false, false, false);
        }
    }

    private void delay(long milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private void change(boolean red, boolean green, boolean blue) {

        ledRed.off();
        ledGreen.off();
        ledBlue.off();

        if (red) {
            ledRed.on();
        }

        if (green) {
            ledGreen.on();
        }

        if (blue) {
            ledBlue.on();
        }
    }

    private void purple() {
        change(138, 43, 226);
    }

    private void white() {
        change(255, 255, 255);
    }

    private void greenTurkey() {
        change(0, 199, 140);
    }

    private void change(int red, int green, int blue) {
        ledRed.on(red);
        ledGreen.on(green);
        ledBlue.on(blue);
    }


}
